﻿using Microsoft.CodeAnalysis.CSharp;
using System.CodeDom.Compiler;

namespace ShadowCode.Injection.Injections;
public class ConstructorUnit(TransformData data, ConstructorDeclarationSyntax syntax)
    : InjectionUnitBase(data)
{
    public override SyntaxNode? Node { get; set; } = syntax;

    /// <summary>
    /// 被标记特性的构造函数
    /// </summary>
    public IMethodSymbol Constructor { get; } =
        data.GetDeclaredSymbol(syntax) as IMethodSymbol
        ?? throw new Exception($"构造函数不应为空:{syntax}");

    protected override string CreateGroupKey() =>
        Constructor.ContainingType.ToDisplayString();

    protected override INamedTypeSymbol CreateTypeDeclaration() =>
        Constructor.ContainingType;

    internal override void ImplementBuild(InjectionAttribute attribute,
        IndentedTextWriter writer, List<string> arguments)
    {
        var implementType = attribute.ReplaceGeneric.TmplementType;
        arguments.Add("implement");
        var methodBody = attribute.IsKeyed ?
            "static object implement(IServiceProvider s, object? k) => new" :
            "static object implement(IServiceProvider s) => new";

        writer.WriteLine($"{methodBody} {implementType.ToDisplayString()}");
        writer.WriteLine("(");

        var last = Constructor.Parameters.LastOrDefault();
        foreach (var p in Constructor.Parameters)
        {
            writer.WriteLine($"\t// {p.Name} :");
            var code = GetCode(p, attribute);
            if (p.Equals(last, SymbolEqualityComparer.Default))
            {
                writer.WriteLine($"\t{code}");
            }
            else
            {
                writer.WriteLine($"\t{code} ,");
            }
        }
        writer.WriteLine(");");
    }

    private static string GetCode(IParameterSymbol p, InjectionAttribute attribute)
    {
        var pType = p.Type.ToDisplayString();
        var require = p.IsOptional ? "" : "Required";
        foreach (var item in p.GetAttributes())
        {
            var fullName = item.AttributeClass?.ToDisplayString();
            if (fullName is null) break;

            if (fullName is "Microsoft.Extensions.DependencyInjection.FromKeyedServicesAttribute")
            {
                var argument = item.ConstructorArguments[0].ToCSharpString();
                return $"s.Get{require}KeyedService<{pType}>({argument})";
            }

            if (fullName is "Microsoft.Extensions.DependencyInjection.ServiceKeyAttribute")
            {
                if (attribute.IsKeyed) return GetServiceKeyCode(p, attribute);
                return $"default({pType})";
            }
        }
        return $"s.Get{require}Service<{pType}>()";
    }

    private static string GetServiceKeyCode(IParameterSymbol p, InjectionAttribute attribute)
    {
        var typeCode = p.Type.ToDisplayString();
        return $"k is {typeCode} v ? v : throw new Exception(\"参数{p.Name} 和 Keye 类型不一致!\")";
    }

    internal override bool CanSimple => Declaration.Constructors.Length is 1;

}